iT邦幫忙

2025 iThome 鐵人賽

DAY 2
1
Rust

30天解鎖 Rust 開發者工具箱系列 第 2

「Day 02」Cargo Is All You Need

  • 分享至 

  • xImage
  •  

https://ithelp.ithome.com.tw/upload/images/20250916/20177832OhQxJvN1RY.jpg
圖:“Rust 的吉祥物 Ferris the Crab 擁有強壯的肌肉,正扛著一堆木箱,在崎嶇的山路上行走”,gemini-2.5-flash-preview,2025年09月16日。

前言:你需要穩定的骨架

Rust 是門「重編譯,輕執行」的程式語言,也相對年輕,必然也都看著各前輩們負重前行,所以 Rust 一誕生就自帶了強壯穩定的骨架,好讓它能夠讓編寫出來程式碼在編譯階段就做完檢查、優化等,產生高效能、安全的軟體。如果沒有一個穩定的骨架,幾乎是難以做到既要、又要、還要的。

學習一門新的語言,不免俗的一定要到它的官方網站查看,Rust 官方網站,這裡有你一切需要的標準答案!絕大部分工程面的問題,你都可以在這邊找到答案,至少能解決90%以上的問題,剩下的10%問題,也有可能不是軟體工程的問題,而是你老闆的問題 XD(誤。這當然是句玩笑話!

但,若遇到這樣的情景,Rust 的骨架體系是能夠很明確地、不斷地提醒你「行不通」。換句話來說,是不是就在更早的階段,甚至是想法嚐鮮、實驗階段就提醒你是不是在思考這類問題時,方向完全錯了!某程度來說,不也挺浪漫的嗎?XD

以下表格我也統整了常見,不見得常用的文檔與經驗分享:

網站 解釋
The Rust Programming Language 這就是 Rust 的聖經,語法該如何寫都在這,標準課本。
Rust By Example 透過範例學習,不害怕錯中學,就從這邊開始吧。
The Rust Standard Library 標注函式庫的技術說明文件(例如:Vec, HashMap 等等),就是字典。
The Rust Edition Guide 詳細說明了每個版本帶來了哪些變化,以及如何將專案從舊版本遷移到新版本,或許到超大型專案才會願意查看吧(誤。
The Cargo Book Cargo的完整使用手冊,但通常 cargo --help 就好了啦。
The rustdoc book 教你如何讓你的程式碼附帶技術文件,往專業化和發佈 crate 的時候,還是照著規則描述,會好管理很多。
The rustc book 編譯器之書,當被編譯器支配的恐懼來到極點後,就會默默打開,然後討厭它,接受它,喜歡它,成為它。
Rust error codes index 編譯時期的錯誤列表,console 看不懂就上來看解釋吧!但通常 rustc --explain E0308 就好了啦。

編譯器:嚴師出不出高徒不知道,但嚴師就是嚴師

地基打得穩,房子才蓋得高。必備的工具們哪能不介紹!

  • rustc:Rust 的核心編譯器,由 Rust 編寫,就是那位「嚴師」。不過實際上 rustc 並不會將 Rust 程式碼直接編譯成機械碼,而是會編譯成 LLVM IR,LLVM 會自動將其編譯成機械碼後,即可執行。正因如此,你會聽到有人說:“Rust 是由 Rust 編寫,但離不開 C++”。
  • rustup:Rust 工具鏈(Toolchain)大總管,讓你輕鬆安裝、更新,甚至切換不同版本的 Rust。
  • cargo:Rust 專案管理套件,但我願稱它為「骨架」。它就是你開發生命週期中可以說唯一要打交道的工具,從專案建立、編譯、套件管理都它統一搞定。
  • rust-analyzer:這是 Rust 的 LSP(Language Server Protocol),功能強大,推薦安裝。程式碼自動補全、錯誤提示等等樣樣精通的精靈助手,它讓你在那位「嚴師」還沒罵你之前,就先提醒你。唯一要注意的是因為是 LSP,在背景會自動執行,會相當耗費 CPU 資源,可在 IDE 中自行關閉或暫停。

工具準備:開始左腳踩右腳升天

Rustc 編譯器與 Cargo 專案管理版本查看,以下為本系列鐵人賽中所使用的版本。不用過度擔心版本問題! 根據我的開發經驗,Rustc 和 Cargo 的版本迭代對日常開發的實質影響很有限。

rustc --version # rustc 1.89.0 (29483883e 2025-08-04)
cargo --version # cargo 1.89.0 (c24e10642 2025-06-23)

Cargo 建立新專案

# 建立一個名為 "my_app" 的新專案
cargo new my_app
cd my_app

# 專案結構解析(一):默認
my_app/
├── Cargo.toml          # 專案配置檔案
├── src/                # 原始碼目錄
│   └── main.rs         # 主程式檔案
└── .gitignore          # Git 忽略檔案(自動建立)

Cargo 添加依賴

# 添加 serde 套件(用於 JSON 處理)
cargo add serde

# 添加帶有功能的套件
cargo add serde --features derive

# 添加特定版本
cargo add rand@0.8

修改 Cargo.toml 手動添加

[dependencies]
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"

使用第三方套件

在程式碼中使用新添加的套件:(趕進度了,一開始寫就該站在巨人的肩膀上!)

// 引入 serde 庫的 Serialize 和 Deserialize 特徵
// 用於 JSON 序列化和反序列化
use serde::{Deserialize, Serialize};

// 定義 Person 結構體
// 使用 Serialize, Deserialize 特徵來支援 JSON 序列化
#[derive(Serialize, Deserialize, Debug, Clone)]
struct Person {
    name: String,
    age: u32,
    money: f64,
}

// Person 結構體的實作區塊
impl Person {
    // 建構函數(關聯函數)
    // 建構函數 - 用於創建新的 Person 實例
    pub fn new(name: String, age: u32, money: f64) -> Self {
        Person { name, age, money }
    }

    // 取得金錢的函數
    pub fn get_money(&self) -> f64 {
        self.money
    }
}

// 計算總金錢的函數:累加每個人的金錢並返回總和
fn sum_money(people: &[Person]) -> f64 {
    let mut total = 0.0;
    for person in people {
        total += person.get_money();
    }
    total
}

fn main() {
    // 創建帶有金錢的 Person 結構體
    let alice = Person::new("Alice".to_string(), 30, 100.50);
    let bob = Person::new("Bob".to_string(), 25, 75.25);
    let charlie = Person::new("Charlie".to_string(), 35, 200.00);

    // 創建個人巨集
    let people = vec![alice, bob, charlie];

    // 計算總金額
    let total_money = sum_money(&people);
    println!("所有人的總金額:${:.2}", total_money);

    // 印出每個個人的金額
    for person in &people {
        println!("{} 擁有 ${:.2}", person.name, person.get_money());
    }

    // 印出 JSON 格式
    println!("\n=== JSON 格式 ===");
    for person in &people {
        let json = serde_json::to_string(person).unwrap();
        println!("{}", json);
    }
}

齒輪開始轉動:編譯與執行

Cargo 核心三劍客:cargo checkcargo buildcargo run,Rust 開發者下意識的動作。口訣就是:cargo check 查語法、cargo run 看效果、cargo build 伸懶腰。以下表格說明了功能:

指令 執行檔 功能
cargo check 編譯器各種檢查,會產生中間檔案,故第二次僅檢查有更動的程式碼(build 與 run 皆是)
cargo run 有+執行 編譯爲可執行檔後,自動執行
cargo build 編譯為可執行檔

以下表格說明 build 與 run 常見指令,以 build 為範例,但 run 共用指令參數。

指令 功能
cargo build 編譯專案,產生未經優化的開發版本執行檔
cargo build --release 編譯專案,產生完全優化的發佈版本執行檔
cargo build --bin <name> 僅編譯 src/bin<name> 檔案成執行檔
cargo build --example <name> 僅編譯 examples<name> 範例檔案成執行檔

測...測試:我知道,但看著都 ...ok 情緒價值會給很滿

單元測試

src/main.rs 的結尾添加測試:

#[cfg(test)]
mod tests {
    use super::*;

    // 測試 Person 結構體的 get_money 方法
    #[test]
    fn test_get_money() {
        let person = Person::new("Alice".to_string(), 30, 100.50);
        assert_eq!(person.get_money(), 100.50);
    }

    // 測試 sum_money 函數
    #[test]
    fn test_sum_money() {
        let people = vec![
            Person::new("Alice".to_string(), 30, 100.50),
            Person::new("Bob".to_string(), 25, 75.25),
            Person::new("Charlie".to_string(), 35, 200.00),
        ];
        assert_eq!(sum_money(&people), 375.75);
    }
}

執行測試

# 運行所有測試
cargo test

# 運行特定測試
cargo test test_get_money
cargo test test_sum_money

# 運行並顯示詳細輸出
cargo test -- --nocapture

指令執行 cargo test 後,你應該會看到類似輸出:(都...ok,一日成就達成)

    Finished `test` profile [unoptimized + debuginfo] target(s) in 0.62s
     Running unittests src/main.rs (target/debug/deps/cargo_tutorial-f11451fb6a32d6c5)

running 2 tests
test tests::test_get_money ... ok
test tests::test_sum_money ... ok

test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

上一篇
「Day 01」序:開啟一段 Rust 的冒險吧!
下一篇
「Day 03」精確收納:cargo module
系列文
30天解鎖 Rust 開發者工具箱3
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言